package com.itheima.spring.beans;


import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;

/**
 * IOC容器创建bean实例,就得告诉IOC容器需要创建什么样的bean
 * BeanDefinition描述一个bean实例
 */
public interface BeanDefinition {

    String SCOPE_SINGLETON = "singleton";

    String SCOPE_PROTOTYPE = "prototype";

    /**
     * 类:new 构造方法的方式创建bean时，需要告诉bean工厂怎么获取类的名称
     */
    Class<?> getBeanClass();

    /**
     * Scope
     */
    String getScope();

    /**
     * 是否单例
     */
    boolean isSingleton();

    /**
     * 是否原型
     */
    boolean isPrototype();

    /**
     * 工厂bean名：成员工厂方法的方式创建bean时,需要告诉bean工厂怎么获取工厂bean名
     */
    String getFactoryBeanName();

    /**
     * 工厂方法名:静态工厂方法的方式创建bean时,需要告诉bean工厂怎么获取工厂方法名
     */
    String getFactoryMethodName();

    /**
     * 初始化方法
     */
    String getInitMethodName();

    /**
     * 销毁方法
     */
    String getDestroyMethodName();

    /**
     * 下面的四个方法是供beanFactory中使用的
     *
     * 1:获取构造方法
     */

    public Constructor<?> getConstructor();

    /**
     * 缓存构造方法
     */
    public void setConstructor(Constructor<?> constructor);

    /**
     * 获取工厂方法
     */
    public Method getFactoryMethod();

    /**
     * 缓存工厂方法
     * @param factoryMethod
     */
    public void setFactoryMethod(Method factoryMethod);


    /**
     * 校验bean定义的合法性
     */
    default boolean validate() {
        // 没定义class,工厂bean或工厂方法没指定，则不合法。
        if (this.getBeanClass() == null) {
            if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())) {
                return false;
            }
        }

        // 定义了类，又定义工厂bean，不合法
        if (this.getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())) {
            return false;
        }

        return true;
    }


    /**
     * 获取参数构造值
     * @return
     */
    List<?> getConstructorArgumentValues();

    /**
     * 获得属性依赖定义的方法
     *
     */
    List<PropertyValue> getPropertyValues();


    public Object[] getConstructorArgumentRealValues();

    public void setConstructorArgumentRealValues(Object[] values);


}
